The present invention is generally directed to the control of process threads in a data processing system. More particularly, the present invention is directed to the control of process threads that extend across protocol layers. Even more particularly, the present invention is directed to the use of locking mechanisms which have low impact on system performance but which still provide safe thread and data handling.
As used herein, a “mutual exclusion lock,” or just “lock” for short, is a synchronization service which is employed in data processing systems and which is used to ensure exclusive access to data shared between threads so that shared data is always seen by the threads in a consistent state.
Protocol layering is a common approach to building complex communication protocols. However, the resulting layer structure is also criticized for its performance overhead. One of the typical overhead “hits” incurred in thread-safe protocol layering is double locking. This means that lock mechanisms are invoked in multiple layers for a single thread. There is no coordination of locking between layers. Yet locking mechanisms are still required for process and data integrity.
Solely for the purposes of clarity and consistency in the present description, in the protocol layering discussions herein, the protocol above is defined to be the upper layer protocol (ULP) and the protocol below is defined to be the lower layer protocol. Both the upper and the lower layer protocols use locking to guarantee thread safety. A user's call to the upper layer protocol's Application Program Interface (API) typically results in the following exemplary down-call sequence.
The upper layer protocol:
1. Acquire ULP lock
2. Request/Event/Data preprocessing
3. Release ULP lock
4. Call to the lower layer protocol's API
The lower layer protocol:
4.1 Acquire LLP lock
4.2 Request/Event/Data processing
4.3 Release LLP lock
4.4 Return to the upper layer protocol
The upper layer protocol:
5. Reacquire ULP lock
6. Request/Event/Data postprocessing
7. Release ULP lock
8. Return to the user
Also, the lower layer protocol can handle synchronous/asynchronous events and generates callbacks to the upper layer protocol, resulting in the following exemplary up-call sequence.
The lower layer protocol:
1. Acquire LLP lock
2. Event preprocessing
3. Release LLP lock
4. Callback to the upper layer protocol
The upper layer protocol:
4.1. Acquire ULP lock to protect the upper layer protocol's data structure
4.2. Event processing
4.3. Release ULP lock before returning to the lower layer protocol
4.4. Return to the lower layer protocol
The lower layer protocol:
5. Reacquire LLP lock
6. Event postprocessing
7. Release LLP lock
8. End of event handling
It is also pointed out that up-call sequences and down-call sequences may be embedded in each other, depending on whether the layering allows it or not. Clearly, both sequences (threads or thread portions) acquire and/or release two locks. This is a very expensive operation in terms of the utilization of system time and resources. On some systems it is worse than others but often depends on the application itself. It also can be argued that Steps 3 and 5 in the two scenarios shown above are not necessary because there is no circular dependency (for example, with an up-call holding lock B and waiting for lock A while a down-call is holding lock A and is waiting for lock B). In this situation there is no deadlock situation.